<template>
  <div class="table-list">
    <!--筛选区域，columnCfg中没有筛选配置则不显示-->
    <div class="filter-box" v-if="showFilter">
      <div class="condition-box" ref="filterBox">
        <template v-for="(column, prop) in columnCfg">
          <div
            class="condition"
            v-if="column.hasOwnProperty('filter')"
            :key="prop"
            :style="{ width: column.filter.width }"
          >
            <template v-if="column.filter.type === ':slot'">
              <label v-show="!column.filter.hideLabel">{{
                column.filter.label || column.label
              }}</label>
              <div style="flex: 1">
                <slot :name="column.filter.slot"></slot>
              </div>
            </template>
            <template v-else>
              <label v-show="!column.filter.hideLabel">{{
                column.filter.label || column.label
              }}</label>
              <filter-input
                :config="column"
                v-model="column.filter.value"
                :prop="prop"
                @change="setFilter"
              ></filter-input>
            </template>
          </div>
        </template>
        <div class="condition" v-if="!isFilterFold">
          <el-button type="primary" @click="refreshData(1)" :disabled="loading"
            >查询</el-button
          >
          <el-button @click="resetFilter" :disabled="loading">重置</el-button>
          <el-button
            v-if="showFilterMore"
            icon="el-icon-arrow-up"
            type="primary"
            class="more-btn"
            @click="toggleMore"
          />
        </div>
      </div>
      <div class="condition-more" v-if="isFilterFold">
        <div class="condition" style="margin-right: 0">
          <el-button type="primary" @click="refreshData(1)">查询</el-button>
          <el-button @click="resetFilter">重置</el-button>
          <el-button
            v-if="showFilterMore"
            icon="el-icon-arrow-down"
            type="primary"
            class="more-btn"
            @click="toggleMore"
          />
        </div>
      </div>
    </div>
    <!--筛选区域与表格间自定义内容-->
    <div class="insert">
      <slot></slot>
    </div>
    <!--数据表格-->
    <div class="table">
      <el-table
        ref="dataTable"
        :data="data"
        v-loading="loading"
        :highlight-current-row="selectType === 'single'"
        style="width: 100%"
        :header-cell-class-name="headerCellClassName"
        :border="border"
        :size="size"
        v-bind="$attrs"
        @selection-change="handleSelectionChange"
        @sort-change="handleSortChange"
      >
        <el-table-column
          v-if="selectType === 'multiple'"
          :selectable="selectable"
          type="selection"
          align="center"
          width="60"
        ></el-table-column>
        <template v-for="(column, prop) in columnCfg">
          <el-table-column
            v-if="!column.hidden && isExistColumn(column)"
            :key="prop"
            :prop="prop"
            :width="column.width * (disableWidthRate ? 1 : widthRate)"
            :min-width="column.minWidth"
            :align="column.align"
            :sortable="column.sortable"
            :sort-by="prop"
            :show-overflow-tooltip="column.overflowTip"
            :class-name="column.class"
            :label="column.label"
            :type="column.type"
          >
            <template slot-scope="scope">
              <div :style="column.style">
                <!--自定义html内容-->
                <template v-if="prop === ':slot' || column.slotName">
                  <slot :name="column.slotName" :row="scope.row"></slot>
                </template>
                <!--操作列，key为:action-->
                <div v-else-if="prop === ':action'" class="row-action">
                  <template v-for="btn in column.actionArr">
                    <el-link
                      :style="{
                        margin: '0 4px',
                        color:
                          btn.btnType === 'del' || btn.label === '删除'
                            ? '#F56C6C'
                            : '#0D48CE'
                      }"
                      :icon="btn.icon"
                      :title="btn.title"
                      :underline="false"
                      v-if="btnCondition(btn, scope.row)"
                      :type="btn.btnType || 'default'"
                      @click.stop="$emit(btn.event, scope.row)"
                      >{{ btn.label }}
                    </el-link>
                  </template>
                </div>
                <!--列内容可点击-->
                <el-link
                  v-else-if="column.link"
                  :type="column.link.type"
                  @click.stop="$emit(column.link.event, scope.row)"
                >
                  <cell-text
                    :value="scope.row[prop]"
                    :dict-key="column.dictKey"
                  ></cell-text>
                </el-link>
                <!--默认-->
                <template v-else>
                  <status-tag :type="column.tag" :value="scope.row[prop]">
                    <cell-text
                      :value="scope.row[prop]"
                      :dict-key="column.dictKey"
                      :class="{ 'single-line': singleLine }"
                    ></cell-text>
                  </status-tag>
                </template>
              </div>
            </template>
          </el-table-column>
        </template>
      </el-table>
    </div>
    <!--页码显示-->
    <el-pagination
      class="pagination"
      v-if="showPagination"
      :current-page="pagination.pageNum"
      :page-size="pagination.pageSize"
      :page-sizes="[10, 20, 30, 40]"
      layout="total, sizes, prev, pager, next, jumper"
      :total="totalSize"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>

<script>
/**
 * 数据表格组件，封装筛选框，表格，及页码组件
 * 筛选区域，及表格列支持slot自定义，用以支持不同显示需求
 * 筛选及表格间区域支持slot自定义内容
 * 表格列支持自动以slot，支持内容添加click响应，支行持操作动作，支持按条件显示操作动作
 * 操作显示条件使用正则进行匹配
 * columnCfg使用对象形式，方便初始配置
 * 使用说明查看manual.md
 */
import FilterInput from "./FilterInput";
import CellText from "./CellText";
import { isExistColumn } from "@/utils/table-column";
let filterLineHeight = 40; //筛选区域单行高度，修改输入框高度后需要调整此参数

export default {
  name: "index",
  components: { CellText, FilterInput },
  props: {
    //表格数据
    data: {
      type: Array,
      required: true,
    },
    //列数据
    columnCfg: {
      type: Object,
      required: true,
    },
    //数据加载中
    loading: {
      type: Boolean,
      default: false,
    },
    //多选or单选 multiple/single
    selectType: {
      type: String,
      default: "",
    },
    //多选框禁用选项
    selectable: Function,
    //尺寸
    size: {
      type: String,
      default: "normal",
    },
    //禁用宽度随窗口变化
    disableWidthRate: {
      type: Boolean,
      default: false,
    },
    //当前页码
    currentPage: {
      type: Number,
      default: 1,
    },
    //每页数量
    pageSize: {
      type: [Number, String],
      default: 10,
    },
    //数据总数
    totalSize: {
      type: Number,
      default: 0,
    },
    //超长数据单行显示
    singleLine: {
      type: Boolean,
      default: false,
    },
    //显示翻页功能区
    showPagination: {
      type: Boolean,
      default: true,
    },
    //筛选区域超长是否自动收起
    filterFold: {
      type: Boolean,
      default: true,
    },
    border: {
      type: Boolean,
      default: false,
    },
    headerCellClassName: {
      type: String,
      default: "headerCellClassName",
    },
    //自定义排序字段
    handleSortfield: Function,
  },
  data() {
    return {
      isExistColumn: isExistColumn,
      retParams: {}, //筛选及翻页请求参数
      pagination: {
        pageNum: 1,
        pageSize: 10,
      },
      multipleSelection: [], //多选内容
      isFilterFold: false, // 是否折叠筛选区域
      showFilterMore: false, //筛选区域是否大于一行，控制展开收起按钮显示
      widthRate: 1,
    };
  },
  created() {
    if (this.pageSize) {
      this.pagination.pageSize = this.pageSize;
    }
    if (this.currentPage) {
      this.pagination.pageNum = this.currentPage;
    }
  },
  watch: {
    currentPage: {
      handler(nv) {
        this.pagination.pageNum = nv;
      },
      immediate: true,
    },
  },
  mounted() {
    if (
      this.showFilter &&
      this.filterFold &&
      this.$refs.filterBox.clientHeight > filterLineHeight
    ) {
      this.showFilterMore = true;
      this.isFilterFold = true; //多行时，默认为收起状态
      this.$refs.filterBox.style.height = filterLineHeight + "px";
    }
    this.$_resizeHandler();
  },

  beforeMount() {
    window.addEventListener("resize", this.$_resizeHandler);
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.$_resizeHandler);
  },
  computed: {
    //遍历columnCfg对象，查看是否存在filter配置，控制筛选区域显示
    showFilter() {
      for (let prop in this.columnCfg) {
        if (this.columnCfg[prop].hasOwnProperty("filter")) {
          return true;
        }
      }
      return false;
    },
  },
  watch: {
    currentPage(to) {
      this.pagination.pageNum = Number(to);
    },
    pageSize(to) {
      this.pagination.pageSize = Number(to);
    },
  },
  methods: {
    $_resizeHandler() {
      let width = this.$refs.dataTable.$el.clientWidth;
      this.widthRate =
        width > 1000 ? this.$refs.dataTable.$el.clientWidth / 1000 : 1;
    },
    //展开折叠筛选区域
    toggleMore() {
      this.isFilterFold = !this.isFilterFold;
      this.isFilterFold
        ? (this.$refs.filterBox.style.height = filterLineHeight + "px")
        : (this.$refs.filterBox.style.height = "");
    },
    //操作按钮条件显示处理
    btnCondition(btn, rowData) {
      if (btn.hasOwnProperty("condition")) {
        let check = false;
        for (let key in btn.condition) {
          if (!new RegExp(btn.condition[key]).test(rowData[key])) {
            return false; //有一个条件不满足则直接返回false
          } else {
            check = true;
          }
        }
        return check;
      } else {
        return true;
      }
    },
    btnAuthCheck(btn) {
      if (btn.hasOwnProperty("btnAuth")) {
        return (
          this.$store.state.permission.btnAuth.indexOf(
            this.$route.path + "{" + btn.btnAuth + "}"
          ) > -1
        );
      } else {
        return true;
      }
    },
    //设置当前页码
    setCurrentPage(pageNum) {
      this.pagination.pageNum = pageNum;
    },
    //设置当前选中行
    setCurrentRow(row) {
      this.$refs.dataTable.setCurrentRow(row);
    },
    //设置多选选中行
    setSelectRows(rows) {
      rows.forEach((row) => {
        this.$refs.dataTable.toggleRowSelection(row, true);
      });
    },
    //单行点击
    handleRowClick(row) {
      if (this.selectType === "multiple") {
        this.$refs.dataTable.toggleRowSelection(row);
      }
      this.$emit("row-click", row);
    },
    //多选状态改变
    handleSelectionChange(valArr) {
      this.multipleSelection = valArr;
      console.log("valArr", valArr);
      this.$emit("selection-change", valArr);
    },
    //页码每页大小改变
    handleSizeChange(val) {
      this.pagination.pageSize = val;
      this.refreshData(1);
    },
    //当前页码改变
    handleCurrentChange(val) {
      this.refreshData(val);
    },
    //通过后台api排序，驼峰转下划线后按照sql格式拼接
    handleSortChange(sortConfig) {
      if (sortConfig.column.sortable === "custom") {
        let params = {};
        if (sortConfig.prop && sortConfig.order) {
          if (this.handleSortfield) {
            params = this.handleSortfield(sortConfig.prop, sortConfig.order);
          } else {
            params = {
              orderByClause:
                sortConfig.prop.replace(/([A-Z])/g, "_$1").toLowerCase() +
                "_" +
                sortConfig.order.replace("ending", ""),
            };
          }
        } else {
          if (this.handleSortfield) {
            params = this.handleSortfield(
              sortConfig.prop,
              sortConfig.order,
              "close"
            );
          } else {
            params = { orderByClause: "" };
          }
        }
        Object.assign(this.retParams, params);
        this.refreshData(1);
      }
      //适应新的后端对接字段 2023 9
      // if(sortConfig.column.sortable === )
      this.$emit("Sort-change", sortConfig);
    },
    //修改筛选条件，修改后需要重置页码
    setFilter({ key, val }) {
      this.retParams[key] = val;
      //this.refreshData(1);
    },
    //重置筛选框显示内容
    resetFilterValue() {
      for (let key in this.columnCfg) {
        if (this.columnCfg[key].hasOwnProperty("filter")) {
          this.$set(this.columnCfg[key].filter, "value", "");
        }
      }
    },
    clearSort() {
      this.$refs.dataTable.clearSort();
    },
    //重置按钮
    resetFilter() {
      this.resetFilterValue();
      this.retParams = {};
      this.refreshData(1, true);
    },
    /**
     * 更新列表数据，提交更新事件
     * @param pageNum 页码，更新筛选条件时需要重置页码为1
     * @param resetFilter
     */
    refreshData(pageNum = 1, resetFilter) {
      this.pagination.pageNum = pageNum;
      Object.assign(this.retParams, this.pagination);
      this.$emit("refresh-list", this.retParams, resetFilter);
      console.log(this.retParams, resetFilter);
    },
  },
};
</script>

<style scoped lang="scss">
.table-list {
  .filter-box {
    margin-bottom: 20px;
    display: flex;

    .btn {
      min-width: 72px;
    }

    .condition-box {
      flex: 1;
      display: flex;
      flex-wrap: wrap;
      overflow: hidden;

      .condition {
        margin-right: 16px;
        margin-top: 8px;
        display: flex;
        align-items: center;
        width: 300px;

        &:last-child {
          margin-right: 0;
        }

        label {
          display: inline-block;
          font-weight: normal;
          text-align: right;
          margin-right: 8px;
          flex-wrap: nowrap;
        }
      }
    }

    .condition-more {
      padding-top: 8px;
      padding-left: 8px;

      .condition {
        margin-right: 0;
      }
    }

    .more-btn {
      padding-left: 8px;
      padding-right: 8px;
      //width: 60px;
      min-width: 40px;
    }
  }

  .insert {
    //margin-bottom: 20px;
  }

  .table {
    //margin-top: 20px;

    .row-action {
      display: flex;
      flex-wrap: wrap;
      .action-link {
        margin: 0 5px;
      }
    }

    .single-line {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      height: 24px;
      line-height: 24px;
    }
  }

  .pagination {
    margin: 20px 0;
    padding-top: 6px;
    text-align: center;
  }
}
::v-deep .headerCellClassName:first-child {
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
}
::v-deep .headerCellClassName {
  background-color: #f7f7f7 !important;
}
::v-deep .headerCellClassName:nth-last-child(2) {
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}
.table {
  transition: width 0.15s;
  -webkit-transition: width 0.15s;
  -moz-transition: width 0.15s;
  -webkit-transition: width 0.15s;
  -o-transition: width 0.15s;
}
</style>
